import can
import cantools
import threading
import os
import sys
import time
import datetime
from win32com import client

# 使用报文转换字符串，使用Sys_State判断急停状态

# 同星数据存储路径
recorder_file_name_prefix = "DHT120B_T250724H0322_ELP"
INCA_recoder_file_name = ""
test_name_string = ""
folder_path = f"D:/{recorder_file_name_prefix}"


# 添加DBC解析和消息配置
db = cantools.db.load_file(
    "Standard_CAN_2025_0703_with_ELP_INCA_modified_by_LFF_20250813.dbc"
)  # 加载DBC文件
msg1 = db.get_message_by_name("testFromPython_0")  # 替换实际报文名称
msg2 = db.get_message_by_name("AOPxxFromINCA")

# 添加共享变量存储INCA读取值
sharing_values = {
    "AOPRx_ActualSpeed_MP": 0.0,
    "AOPRx_BatteryVoltage_MP": 0.0,
    "AOPTx_TargetSpeed_MP": 0.0,
    "testModeFromBench": 0,  # 0:无,1：2.1模式, 2：2.2模式, 3：4.1模式, 4：4.2模式
    "testTempFromBench": 0,
    "testLowVoltageFromBench": 0.0,
    "testConditionFromBench": 0,  # 0:无,1:A,2:B,3:C,4:D,5:E
    "testStartFlagFromBench": 0,
    "testSerialNumberFromBench": 0,  # 试验编号与大纲对应
    "testDuanLuBaoHuTypeFromBench": 0,  # 各信号线对正负短路
    "testZhongDuanFromBench": 0,  # 1:PCM, 2:EOP 3以上各PIN
    "testRecorderStartFlagFromPython": 0,
    "testHeartBeatFromPython": 0,  # 心跳信号
    "ES410_AD1_KL30": 0.0,  # ES410系列电压值信号
    "ES410_AD1_KL15": 0.0,
    "ES410_AD1_CPSR": 0.0,
    "ES410_AD1_EOP": 0.0,
    "Sys_State": 0,  # 用来表示是否报停,与F_SPLC.FLG_ESTOP_OK关联
    "RecorderNameSignal_00": 0,  # 用来转成字符串
    "RecorderNameSignal_01": 0,
    "RecorderNameSignal_02": 0,
    "RecorderNameSignal_03": 0,
    "RecorderNameSignal_04": 0,
    "RecorderNameSignal_05": 0,
    "RecorderNameSignal_06": 0,
    "RecorderNameSignal_07": 0,
    "RecorderNameSignal_10": 0,
    "RecorderNameSignal_11": 0,
    "RecorderNameSignal_12": 0,
    "RecorderNameSignal_13": 0,
    "RecorderNameSignal_14": 0,
    "RecorderNameSignal_15": 0,
    "RecorderNameSignal_16": 0,
    "RecorderNameSignal_17": 0,
    "RecorderNameSignal_20": 0,
    "RecorderNameSignal_21": 0,
    "RecorderNameSignal_22": 0,
    "RecorderNameSignal_23": 0,
    "RecorderNameSignal_24": 0,
    "RecorderNameSignal_25": 0,
    "RecorderNameSignal_26": 0,
    "RecorderNameSignal_27": 0,
}


def INCA_Start_RCD():
    global experiment
    try:
        # 直接调用COM接口开始录制
        experiment.StartRecording()
        print("INCA录制已启动")
    except Exception as e:
        print(f"INCA启动录制失败: {e}")
        sys.exit(1)


def INCA_Stop_RCD():
    global experiment
    try:
        # 停止录制并保存
        full_path = f"{folder_path}/{INCA_recoder_file_name}.dat"
        experiment.StopRecording(full_path, "ETASMDF")
        print(f"INCA录制已保存至: {full_path}")
    except Exception as e:
        print(f"INCA停止录制失败: {e}")
        sys.exit(1)


def calculate_test_name_string():
    global test_name_string
    # 定义RecorderNameSignal键的顺序
    recorder_keys = [
        "RecorderNameSignal_00",
        "RecorderNameSignal_01",
        "RecorderNameSignal_02",
        "RecorderNameSignal_03",
        "RecorderNameSignal_04",
        "RecorderNameSignal_05",
        "RecorderNameSignal_06",
        "RecorderNameSignal_07",
        "RecorderNameSignal_10",
        "RecorderNameSignal_11",
        "RecorderNameSignal_12",
        "RecorderNameSignal_13",
        "RecorderNameSignal_14",
        "RecorderNameSignal_15",
        "RecorderNameSignal_16",
        "RecorderNameSignal_17",
        "RecorderNameSignal_20",
        "RecorderNameSignal_21",
        "RecorderNameSignal_22",
        "RecorderNameSignal_23",
        "RecorderNameSignal_24",
        "RecorderNameSignal_25",
        "RecorderNameSignal_26",
        "RecorderNameSignal_27",
    ]

    # 将每个RecorderNameSignal值转换为ASCII字符并连接
    test_name_string = "".join(
        [
            (
                chr(int(sharing_values[key]))
                if 32 <= int(sharing_values[key]) <= 126
                else ""
            )
            for key in recorder_keys
        ]
    )
    return test_name_string


def calculate_INCA_recorder_file_name():
    timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H_%M_%S")  # 新增时间戳
    calculate_test_name_string()
    global INCA_recoder_file_name
    INCA_recoder_file_name = (
        f"{recorder_file_name_prefix}_{test_name_string}_{timestamp}"
    )
    return INCA_recoder_file_name


def inca_reader_thread(experiment, interval=1.0):
    """INCA变量读取线程"""
    import pythoncom  # 新增COM初始化

    pythoncom.CoInitialize()  # 每个线程需要单独初始化COM

    try:
        variables_read_from_inca = [
            "testStartFlagFromBench",
            "AOPRx_ActualSpeed_MP",
            "AOPRx_BatteryVoltage_MP",
            "AOPTx_TargetSpeed_MP",
            "Sys_State",
            "RecorderNameSignal_00",  # 用来转成字符串
            "RecorderNameSignal_01",
            "RecorderNameSignal_02",
            "RecorderNameSignal_03",
            "RecorderNameSignal_04",
            "RecorderNameSignal_05",
            "RecorderNameSignal_06",
            "RecorderNameSignal_07",
            "RecorderNameSignal_10",
            "RecorderNameSignal_11",
            "RecorderNameSignal_12",
            "RecorderNameSignal_13",
            "RecorderNameSignal_14",
            "RecorderNameSignal_15",
            "RecorderNameSignal_16",
            "RecorderNameSignal_17",
            "RecorderNameSignal_20",
            "RecorderNameSignal_21",
            "RecorderNameSignal_22",
            "RecorderNameSignal_23",
            "RecorderNameSignal_24",
            "RecorderNameSignal_25",
            "RecorderNameSignal_26",
            "RecorderNameSignal_27",
        ]
        while True:
            try:
                for name in variables_read_from_inca:
                    measureElement = experiment.GetMeasureElement(name)
                    # 添加空值检查
                    if measureElement is None:
                        raise ValueError(f"未找到变量: {name}")
                    sharing_values[name] = measureElement.GetValue().GetFloatPhysValue()
                    # print(f"INCA读取: {name} = {sharing_values[name]}")
                time.sleep(interval)
            except Exception as e:
                print(f"INCA读取错误: {str(e)}")
                print(f"失败变量: {name if 'name' in locals() else '未知'}")
                print(f"实验对象有效性: {experiment is not None}")
                time.sleep(5)
                # break 注释掉break，继续读取，保证掉电时工作
            finally:
                time.sleep(interval)
    finally:
        pythoncom.CoUninitialize()  # 清理COM资源


def send_cyclic_message(msg_config):

    while True:  # 修改循环条件
        try:
            # 从配置中获取参数
            message = msg_config["message"]
            signal_generator = msg_config["signal_generator"]
            interval = msg_config["interval"]

            # 生成信号数据
            signals = signal_generator()
            data = message.encode(signals)

            msg = can.Message(
                arbitration_id=message.frame_id, data=data, is_extended_id=False
            )

            bus.send(msg)
            time.sleep(interval)

        except Exception as e:
            print(f"{message.name} 发送错误: {e}")
            break


# 心跳值更新函数
def update_heartbeat():
    while True:
        # 实现0到3的循环
        sharing_values["testHeartBeatFromPython"] = (
            sharing_values["testHeartBeatFromPython"] + 1
        ) % 4
        time.sleep(0.5)  # 每0.5秒更新一次心跳值


if __name__ == "__main__":

    # 初始化INCA COM接口
    COMServerName = "Inca.Inca"
    inca_obj = client.Dispatch(COMServerName)
    experiment = inca_obj.GetOpenedExperiment()

    # 创建CAN通道
    bus = can.interface.Bus(
        interface="neovi", serial="91277", channel="1", bitrate=500000
    )

    # 启动INCA读取线程
    inca_thread = threading.Thread(
        target=inca_reader_thread, args=(experiment, 0.1), daemon=True
    )
    inca_thread.start()

    # 启动心跳更新线程
    heartbeat_thread = threading.Thread(target=update_heartbeat, daemon=True)
    heartbeat_thread.start()

    # 报文配置列表
    message_configs = [
        {
            "message": msg1,
            "signal_generator": lambda: {
                "testRecorderStartFlagFromPython": sharing_values[
                    "testRecorderStartFlagFromPython"
                ],
                "testHeartBeatFromPython": sharing_values["testHeartBeatFromPython"],
            },
            "interval": 0.5,
        },
        {
            "message": msg2,
            "signal_generator": lambda: {
                "AOPRx_ActualSpeed_fromINCA": sharing_values["AOPRx_ActualSpeed_MP"],
                "AOPRx_BatteryVoltage_fromINCA": sharing_values[
                    "AOPRx_BatteryVoltage_MP"
                ],
                "AOPTx_TargetSpeed_fromINCA": sharing_values["AOPTx_TargetSpeed_MP"],
            },
            "interval": 0.1,
        },
    ]

    # 批量创建发送线程
    for config in message_configs:
        thread = threading.Thread(
            target=send_cyclic_message, args=(config,), daemon=True
        )
        thread.start()

    try:
        recording = False  # 新增录制状态标志
        while True:
            StartFlag = sharing_values["testStartFlagFromBench"]
            SysState = sharing_values["Sys_State"]
            if StartFlag == 1 and not recording:
                INCA_Start_RCD()
                recording = True
                sharing_values["testRecorderStartFlagFromPython"] = 1
                print("开始录制...")

            elif SysState == 0 and recording:
                time.sleep(10)
                calculate_INCA_recorder_file_name()
                INCA_recoder_file_name += "_F"
                INCA_Stop_RCD()
                time.sleep(1)
                print("录制结束 -------")
                sharing_values["testRecorderStartFlagFromPython"] = 0
                recording = False

            elif StartFlag == 0 and recording:
                calculate_INCA_recorder_file_name()
                INCA_Stop_RCD()
                time.sleep(1)
                print("录制结束 -------")
                sharing_values["testRecorderStartFlagFromPython"] = 0
                recording = False

            time.sleep(0.1)
    except KeyboardInterrupt:
        pass
    finally:
        bus.shutdown()
        print("总线已关闭，程序退出")
